use crate::utils::get_reader;
use crate::{process_gen_pass, TextSignFormat};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use blake3::keyed_hash;
use ed25519::signature::{Signer, Verifier};
use ed25519_dalek::{SigningKey, VerifyingKey};
use rand::rngs::OsRng;
use std::fs;
use std::io::Read;
use std::path::Path;
use TextSignFormat::{Blake3, Ed25519};
trait TextSign {
    fn sign(&self, reader: &mut dyn Read) -> anyhow::Result<Vec<u8>>;
}
trait TextVerify {
    fn verify(&self, reader: impl Read, sig: &[u8]) -> anyhow::Result<bool>;
}
trait LoadKey {
    fn load_key(path: impl AsRef<Path>) -> anyhow::Result<Self>
    where
        Self: Sized;
}
pub trait GenerateKey {
    fn generate_key() -> anyhow::Result<Vec<Vec<u8>>>;
}
struct MyBlake3 {
    key: [u8; 32],
}
struct Ed25519Signer {
    key: SigningKey,
}
struct Ed25519Verifier {
    key: VerifyingKey,
}

//函数开始
pub fn process_text_sign(input: &str, key: &str, format: TextSignFormat) -> anyhow::Result<String> {
    let mut reader = get_reader(input)?;
    let signed = match format {
        Blake3 => {
            let signer = MyBlake3::load_key(key)?;
            signer.sign(&mut reader)?
        }
        Ed25519 => {
            let signer = Ed25519Signer::load_key(key)?;
            signer.sign(&mut reader)?
        }
    };
    let signed = URL_SAFE_NO_PAD.encode(signed);
    // println!("{}", signed);
    Ok(signed)
}
pub fn process_text_verify(
    input: &str,
    key: &str,
    sig: &str,
    format: TextSignFormat,
) -> anyhow::Result<bool> {
    let mut reader = get_reader(input)?;
    let sig = URL_SAFE_NO_PAD.decode(sig)?;
    let verified = match format {
        Blake3 => {
            let verifier = MyBlake3::load_key(key)?;
            verifier.verify(&mut reader, &sig)?
        }
        Ed25519 => {
            let verifier = Ed25519Verifier::load_key(key)?;
            verifier.verify(&mut reader, &sig)?
        }
    };
    Ok(verified)
}

pub fn process_generate_key(format: TextSignFormat) -> anyhow::Result<Vec<Vec<u8>>> {
    match format {
        Blake3 => MyBlake3::generate_key(),
        Ed25519 => Ed25519Signer::generate_key(),
    }
}

//定义trait函数
impl TextSign for MyBlake3 {
    fn sign(&self, reader: &mut dyn Read) -> anyhow::Result<Vec<u8>> {
        let mut buf = Vec::new();
        reader.read_to_end(&mut buf)?;
        let data = keyed_hash(&self.key, &buf);
        Ok(data.as_bytes().to_vec())
    }
}
impl TextVerify for MyBlake3 {
    fn verify(&self, mut reader: impl Read, sig: &[u8]) -> anyhow::Result<bool> {
        let mut buf = Vec::new();
        reader.read_to_end(&mut buf)?;
        let hash = keyed_hash(&self.key, &buf);
        Ok(hash.as_bytes() == sig)
    }
}
impl GenerateKey for MyBlake3 {
    fn generate_key() -> anyhow::Result<Vec<Vec<u8>>> {
        let key = process_gen_pass(32, true, true, true, true);
        let key = key.as_bytes().to_vec();
        Ok(vec![key])
    }
}
impl MyBlake3 {
    pub fn new(key: [u8; 32]) -> Self {
        Self { key }
    }
    pub fn try_new(key: &[u8]) -> anyhow::Result<Self> {
        if key.len() < 32 {
            return Err(anyhow::anyhow!("位数不足"));
        }
        let key = &key[..32];
        let key = key.try_into()?;
        let signer = Self::new(key);
        Ok(signer)
    }
}
impl LoadKey for MyBlake3 {
    fn load_key(path: impl AsRef<Path>) -> anyhow::Result<Self> {
        let key = fs::read(path)?;
        Self::try_new(&key)
    }
}

impl GenerateKey for Ed25519Signer {
    fn generate_key() -> anyhow::Result<Vec<Vec<u8>>> {
        let mut rng = OsRng;
        let sk = SigningKey::generate(&mut rng);
        let pk = sk.verifying_key().to_bytes().to_vec();
        let sk = sk.to_bytes().to_vec();
        Ok(vec![sk, pk])
    }
}

impl Ed25519Signer {
    pub fn new(key: &[u8; 32]) -> Self {
        let key = SigningKey::from_bytes(key);
        Self { key }
    }
    pub fn try_new(key: impl AsRef<[u8]>) -> anyhow::Result<Self> {
        let key = key.as_ref();
        let key = (&key[..32]).try_into()?;
        Ok(Self::new(key))
    }
}
impl LoadKey for Ed25519Signer {
    fn load_key(path: impl AsRef<Path>) -> anyhow::Result<Self> {
        let key = fs::read(path)?;
        Self::try_new(key)
    }
}
// ED25519
impl TextSign for Ed25519Signer {
    /// sign the data
    fn sign(&self, reader: &mut dyn Read) -> anyhow::Result<Vec<u8>> {
        let mut buf = Vec::new();
        reader.read_to_end(&mut buf)?;
        Ok(self.key.sign(&buf).to_bytes().to_vec())
    }
}
impl TextVerify for Ed25519Verifier {
    /// verify the signature
    fn verify(&self, mut reader: impl Read, sig: &[u8]) -> anyhow::Result<bool> {
        let mut buf = Vec::new();
        reader.read_to_end(&mut buf)?;
        let sig = (&sig[..64]).try_into()?;
        println!("no1 sig is===> {:?}", &sig);
        let sig = ed25519_dalek::Signature::from_bytes(sig);
        println!("no2 sig is===> {:?}", &sig);
        let ret = self.key.verify(&buf, &sig);
        println!("ret is===> {:?}", &ret);
        Ok(ret.is_ok())
    }
}

impl Ed25519Verifier {
    pub fn try_new(key: impl AsRef<[u8]>) -> anyhow::Result<Self> {
        let key = key.as_ref();
        let key = (&key[..32]).try_into()?;
        let key = VerifyingKey::from_bytes(key)?;
        Ok(Self { key })
    }
}
impl LoadKey for Ed25519Verifier {
    fn load_key(path: impl AsRef<Path>) -> anyhow::Result<Self> {
        let key = fs::read(path)?;
        Self::try_new(key)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_blake3() -> anyhow::Result<()> {
        let signer = MyBlake3::load_key("tests/pass.txt")?;
        let data = b"hello";
        let sig = signer.sign(&mut &data[..])?;
        assert!(signer.verify(&mut &data[..], &sig)?);
        Ok(())
    }
    #[test]
    fn test_ed25519() -> anyhow::Result<()> {
        let sk = Ed25519Signer::load_key("tests/ed25519.sk")?;
        let pk = Ed25519Verifier::load_key("tests/ed25519.pk")?;
        let data = b"hello";
        let sig = sk.sign(&mut &data[..])?;
        assert!(pk.verify(&mut &data[..], &sig)?);
        Ok(())
    }
}
